package me.exchange.com.modules.system.controller;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.exchange.com.aop.log.Log;
import me.exchange.com.config.DataScope;
import me.exchange.com.exception.BadRequestException;
import me.exchange.com.modules.system.domain.FileContent;
import me.exchange.com.modules.system.domain.User;
import me.exchange.com.modules.system.domain.vo.UserPassVo;
import me.exchange.com.modules.system.dto.*;
import me.exchange.com.modules.system.service.AmazonService;
import me.exchange.com.modules.system.service.DeptService;
import me.exchange.com.modules.system.service.RoleService;
import me.exchange.com.modules.system.service.UserService;
import me.exchange.com.utils.BaseUtil;
import me.exchange.com.utils.Result;
import me.exchange.com.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Zheng Jie
 * @date 2018-11-23
 */
@Api(tags = "系统：用户管理")
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Value("${rsa.private_key}")
    private String privateKey;

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserService userService;
    @Autowired
    private DataScope dataScope;
    @Autowired
    private DeptService deptService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private AmazonService amazonService;


    @Log("导出用户数据")
    @ApiOperation("导出用户数据")
    @PostMapping(value = "/list/download")
    @PreAuthorize("@el.check('user:list')")
    public void download(HttpServletResponse response, UserQueryCriteria criteria) throws IOException {
        userService.download(userService.queryAll(criteria), response);
    }

    @Log("上传用户头像")
    @ApiOperation("上传用户头像")
    @PostMapping("/uploadAvatar")
    public ResponseEntity<Object> upload(@RequestParam MultipartFile file){
        FileContent fileContent = null;
        try {
            fileContent = amazonService.upload(file);
        } catch (Exception e) {
            return new ResponseEntity<>(Result.error("用户头像上传失败"),HttpStatus.OK);
        }
        return new ResponseEntity<>(Result.ok("用户头像上传成功").put("userAvtar", fileContent),HttpStatus.OK);

        /*QiniuContent qiniuContent = qiNiuService.upload(file,qiNiuService.find());
        return new ResponseEntity<>(Result.ok("上传用户头像成功").put("userAvtar",qiniuContent),HttpStatus.OK);*/
    }



    @Log("查询用户")
    @ApiOperation("查询用户")
    @PostMapping("/list")
    @PreAuthorize("@el.check('user:list')")
    public ResponseEntity<Object> getUsers(UserQueryCriteria criteria, Pageable pageable){
        if(criteria.getCAdminTime() != null && criteria.getCAdminTime().size()>0){
            if(criteria.getCAdminTime().get(1).before(criteria.getCAdminTime().get(0))){
                return new ResponseEntity<>(Result.error("操作失败，查询时间段设置不正确"),HttpStatus.OK);
            }
        }
        List<UserDto> userInfo =  buildDtos(userService.queryAll(criteria));
        return new ResponseEntity<>(Result.ok("查询用户成功").put("userList",userInfo),HttpStatus.OK);
    }
    @Log("查询用户详情")
    @ApiOperation("查询用户详情")
    @PostMapping(value = "/queryInfo")
    @PreAuthorize("@el.check('user:list')")
    public ResponseEntity<Object> queryInfo(Long id){
        UserDto userInfo = buildDto(userService.findById(id));
        return new ResponseEntity<>(Result.ok("查询用户详情成功").put("userInfo",userInfo), HttpStatus.OK);
    }

    @Log(value="新增用户",code="system_user")
    @ApiOperation("新增用户")
    @PostMapping("/add")
    @PreAuthorize("@el.check('user:add0')")
    public ResponseEntity<Object> create(@Validated @RequestBody User resources){
        if(resources.getRoleId()!=null){
            checkLevel(resources);
        }
        resources.setPassword(passwordEncoder.encode(resources.getPassword()));
        userService.create(resources);
        return new ResponseEntity<>(Result.ok("用户创建成功"),HttpStatus.OK);
    }

    @Log(value="修改用户",code="system_user")
    @ApiOperation("修改用户")
    @PostMapping("/update")
    @PreAuthorize("@el.check('user:edit')")
    public ResponseEntity<Object> update(@Validated(User.Update.class) @RequestBody User resources){
        if(resources.getRoleId()!=null){
            checkLevel(resources);
        }
        UserDto userInfo = userService.findById(resources.getId());
        if(!userInfo.getPassword().equals(resources.getPassword())){
            resources.setPassword(passwordEncoder.encode(resources.getPassword()));
        }
        userService.update(resources);
        return new ResponseEntity<>(Result.ok("用户修改成功"),HttpStatus.OK);
    }

    @Log("获取随机密码")
    @ApiOperation("获取随机密码")
    @PostMapping("/getPassword")
    public ResponseEntity<Object> getPassword(){
        return new ResponseEntity<>(Result.ok("随机密码获取成功").put("password",BaseUtil.getGUID()),HttpStatus.OK);
    }


    @Log(value="修改用户：个人中心",code="system_user")
    @ApiOperation("修改用户：个人中心")
    @PostMapping(value = "/center")
    public ResponseEntity<Object> center(@Validated(User.Update.class) @RequestBody User resources){
        UserDto userDto = userService.findByName(SecurityUtils.getUsername());
        if(!resources.getId().equals(userDto.getId())){
            throw new BadRequestException("不能修改他人资料");
        }
        userService.updateCenter(resources);
        return new ResponseEntity<>(Result.ok("修改成功"),HttpStatus.OK);
    }

    @Log(value="删除用户",code="system_user")
    @ApiOperation("删除用户")
    @PostMapping("/del")
    @PreAuthorize("@el.check('user:del')")
    public ResponseEntity<Object> delete(@RequestBody UserQueryCriteria criteria){
        UserDto user = userService.findByName(SecurityUtils.getUsername());
        for (Long id : criteria.getIds()) {
            Integer currentLevel =  Collections.min(roleService.findByUsersId(user.getId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
            Integer optLevel =  Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
            if (currentLevel > optLevel) {
                throw new BadRequestException("角色权限不足，不能删除：" + userService.findByName(SecurityUtils.getUsername()).getUsername());
            }
        }
        userService.delete(criteria.getIds());
        return new ResponseEntity<>(Result.ok("用户删除成功"),HttpStatus.OK);
    }

    @ApiOperation("修改密码")
    @PostMapping(value = "/updatePass")
    public ResponseEntity<Object> updatePass(@RequestBody UserPassVo passVo){
        // 密码解密
        RSA rsa = new RSA(privateKey, null);
        String oldPass = new String(rsa.decrypt(passVo.getOldPass(), KeyType.PrivateKey));
        String newPass = new String(rsa.decrypt(passVo.getNewPass(), KeyType.PrivateKey));
        UserDto user = userService.findByName(SecurityUtils.getUsername());
        if(!passwordEncoder.matches(oldPass, user.getPassword())){
            throw new BadRequestException("修改失败，旧密码错误");
        }
        if(passwordEncoder.matches(newPass, user.getPassword())){
            throw new BadRequestException("新密码不能与旧密码相同");
        }
        userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass));
        return new ResponseEntity<>(Result.ok("用户密码修改成功"),HttpStatus.OK);
    }

    @ApiOperation("管理员修改用户密码")
    @PostMapping(value = "/adminUpdatePass")
    public ResponseEntity<Object> adminUpdatePass(@RequestBody UserPassVo passVo){
        if(StringUtils.isEmpty(passVo)){
            throw new BadRequestException("用户id不能为空");
        }
        // 密码解密
        RSA rsa = new RSA(privateKey, null);
        String newPass = new String(rsa.decrypt(passVo.getNewPass(), KeyType.PrivateKey));
        UserDto user= userService.findById(passVo.getId());
        if(user!=null){
            userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass));
        }else {
            throw new BadRequestException("用户不存在");
        }
        return new ResponseEntity<>(Result.ok("管理员用户密码修改成功"),HttpStatus.OK);
    }
    /**
     * 如果当前用户的角色级别低于创建用户的角色级别，则抛出权限不足的错误
     * @param resources /
     */
    private void checkLevel(User resources) {
        UserDto user = userService.findByName(SecurityUtils.getUsername());
        Integer currentLevel =  Collections.min(roleService.findByUsersId(user.getId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()));
        Integer optLevel = roleService.findByRoleId(resources.getRoleId());
        if (currentLevel > optLevel) {
            throw new BadRequestException("角色权限不足");
        }
    }


    public  List<UserDto> buildDtos(List<UserDto> u_dtos){
        List<UserDto> new_obj = new ArrayList<>();
        for(UserDto user: u_dtos){
            new_obj.add(buildDto(user));
        }
        return new_obj;
    }

    public  UserDto buildDto(UserDto user){
        DeptSmallDto deptSmallDto= new DeptSmallDto();
        RoleSmallDto roleSmallDto= new RoleSmallDto();
        RoleDto role = roleService.findById(user.getRoleId());
        DeptDto dict = deptService.findById(user.getDeptId());
        deptSmallDto.setId(user.getDeptId());
        deptSmallDto.setName(dict.getName());
        roleSmallDto.setId(user.getRoleId());
        roleSmallDto.setName(role.getRoleName());
        roleSmallDto.setLevel(role.getLevel());
        roleSmallDto.setDataScope(role.getDataScope());
        user.setDept(deptSmallDto);
        user.setRole(roleSmallDto);
        return user;
    }
}
